"""
日志配置管理模块。

提供统一的日志配置接口，支持全局日志级别设置、模块级日志控制和
自定义格式化等功能，确保整个框架的日志行为一致性。
"""

import logging
from typing import Dict, List, Union, Optional
import os
import sys
from functools import lru_cache
from dataclasses import dataclass, field


@dataclass
class LoggingConfig:
    """
    日志配置数据类，集中管理日志设置。

    使用数据类提供类型安全的配置对象，而不是使用普通字典。
    """

    # 全局默认日志级别
    default_level: int = logging.INFO
    # 日志格式
    # format_string: str = "[%(asctime)s][%(levelname)5s][%(filename)s:%(lineno)d][%(name)s][%(message)s]"
    format_string: str = (
        "[%(asctime)s][%(levelname)s][%(filename)s:%(lineno)d]: %(message)s"
    )
    # 日期格式
    date_format: str = "%Y-%m-%d %H:%M:%S"
    # 模块特定的日志级别配置 (模块路径 -> 日志级别)
    module_levels: Dict[str, int] = field(default_factory=dict)
    # 预定义的模块组
    module_groups: Dict[str, List[str]] = field(default_factory=dict)
    # 是否启用控制台输出
    console_output: bool = True
    # 是否启用文件输出
    file_output: bool = False
    # 日志文件路径（当file_output=True时有效）
    log_file: Optional[str] = None
    # 是否使用彩色日志
    use_colors: bool = True
    # 环境变量中的日志级别键
    env_log_level_key: str = "CL_LOG_LEVEL"
    # 最大文件大小（字节）
    max_file_size: int = 10 * 1024 * 1024  # 10MB
    # 保留的日志文件数量
    backup_count: int = 3


# 全局配置单例
_config = LoggingConfig()

# 日志级别映射
_LEVEL_MAPPING = {
    "debug": logging.DEBUG,
    "info": logging.INFO,
    "warning": logging.WARNING,
    "error": logging.ERROR,
    "critical": logging.CRITICAL,
}

# 默认的模块组配置
DEFAULT_MODULE_GROUPS = {
    # Hook相关模块
    "hooks": [
        "continuallearning.models.pefts.common.hook_base",
        "continuallearning.models.pefts.common.hook_manager",
        "continuallearning.models.pefts.lora.lora_hooks",
        "continuallearning.models.pefts.lora.bypass_lora_hooks",
    ],
    # 数据加载相关模块
    "data": [
        "continuallearning.data",
        "continuallearning.data.datasets",
    ],
    # 事件系统相关模块
    "events": [
        "continuallearning.events",
    ],
    # 模型相关模块
    "models": [
        "continuallearning.models",
    ],
}


@lru_cache(maxsize=1)
def get_config() -> LoggingConfig:
    """
    获取全局日志配置。使用LRU缓存以提高性能。

    Returns:
        LoggingConfig: 当前的日志配置
    """
    return _config


def configure_logging(config: Optional[LoggingConfig] = None) -> None:
    """
    使用提供的配置配置日志系统。

    Args:
        config: 日志配置对象，如果为None则使用全局配置
    """
    global _config

    if config:
        _config = config

    # 应用环境变量日志级别
    _apply_environment_settings()

    # 创建和配置根记录器
    _configure_root_logger()

    # 配置模块级日志
    _configure_module_loggers()


def _apply_environment_settings() -> None:
    """应用来自环境变量的设置"""
    env_level = os.environ.get(_config.env_log_level_key)
    if env_level:
        env_level = env_level.lower()
        if env_level in _LEVEL_MAPPING:
            _config.default_level = _LEVEL_MAPPING[env_level]


def _configure_root_logger() -> None:
    """配置根记录器"""
    # 获取根记录器
    root_logger = logging.getLogger()

    # 清除现有处理器
    for handler in root_logger.handlers[:]:
        root_logger.removeHandler(handler)

    # 设置根记录器级别
    root_logger.setLevel(_config.default_level)

    # 创建格式化器
    formatter = logging.Formatter(
        fmt=_config.format_string, datefmt=_config.date_format
    )

    # 添加控制台处理器
    if _config.console_output:
        console_handler = logging.StreamHandler(sys.stdout)
        console_handler.setFormatter(formatter)
        root_logger.addHandler(console_handler)

    # 添加文件处理器
    if _config.file_output and _config.log_file:
        # 使用轮转文件处理器以支持日志文件轮换
        from logging.handlers import RotatingFileHandler

        file_handler = RotatingFileHandler(
            _config.log_file,
            maxBytes=_config.max_file_size,
            backupCount=_config.backup_count,
        )
        file_handler.setFormatter(formatter)
        root_logger.addHandler(file_handler)


def _configure_module_loggers() -> None:
    """配置模块级记录器"""
    # 首先展开模块组
    expanded_module_levels = _config.module_levels.copy()

    # 处理预定义的模块组
    for group, modules in _config.module_groups.items():
        if group in expanded_module_levels:
            level = expanded_module_levels[group]
            # 将组中的每个模块应用相同级别
            for module in modules:
                expanded_module_levels[module] = level

    # 合并默认模块组
    for group, modules in DEFAULT_MODULE_GROUPS.items():
        if group in expanded_module_levels:
            level = expanded_module_levels[group]
            # 将组中的每个模块应用相同级别
            for module in modules:
                expanded_module_levels[module] = level

    # 设置每个模块的日志级别
    for module, level in expanded_module_levels.items():
        if isinstance(level, str):
            level = _LEVEL_MAPPING.get(level.lower(), _config.default_level)
        logging.getLogger(module).setLevel(level)


def get_logger(name: str) -> logging.Logger:
    """
    获取配置的记录器。这是获取日志记录器的推荐方法。

    Args:
        name: 记录器名称，通常是 __name__

    Returns:
        logging.Logger: 已配置的日志记录器
    """
    return logging.getLogger(name)


def set_module_level(module: str, level: Union[int, str]) -> None:
    """
    设置特定模块的日志级别。

    Args:
        module: 模块路径
        level: 日志级别，可以是整数或字符串('debug', 'info'等)
    """
    if isinstance(level, str):
        level = _LEVEL_MAPPING.get(level.lower(), logging.INFO)

    # 更新配置
    _config.module_levels[module] = level

    # 直接应用设置
    logging.getLogger(module).setLevel(level)


def set_level_for_group(group: str, level: Union[int, str]) -> None:
    """
    为预定义的模块组设置日志级别。

    Args:
        group: 模块组名称('hooks', 'data'等)
        level: 日志级别
    """
    if isinstance(level, str):
        level = _LEVEL_MAPPING.get(level.lower(), logging.INFO)

    # 更新组配置
    _config.module_levels[group] = level

    # 如果组存在于预定义组中，立即应用到所有模块
    modules = _config.module_groups.get(group, []) or DEFAULT_MODULE_GROUPS.get(
        group, []
    )
    for module in modules:
        logging.getLogger(module).setLevel(level)


# 模块初始化时自动配置日志
configure_logging()
